// ***************************************************************************************
// Copyright (c) 2023-2025 Peng Cheng Laboratory
// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences
// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip
//
// iEDA is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
//
// See the Mulan PSL v2 for more details.
// ***************************************************************************************
/**
 * @File Name: contest_guide.cpp
 * @Brief :
 * @Author : Yell (12112088@qq.com)
 * @Version : 1.0
 * @Creat Date : 2023-09-15
 *
 */
#pragma once
#include <set>
#include <string>
#include <vector>
#include <unordered_map>

#include "contest_guide.h"
#include "contest_pin.h"
#include "contest_segment.h"
#include <cfloat>
#include "Rectangle.hh"
#include "Point.hh"

namespace ieda_contest {
enum class ContestNET_TYPE { kNoNetType, kClockNet, kResetNet, kSignalNet, kDontCare, kFakeNet };

class ContestNet
{
 public:
  ContestNet() = default;
  explicit ContestNet(std::string name);
  ~ContestNet() = default;
  // getter
  // std::string get_net_name() { return _net_name; }
  std::vector<ContestGuide>& get_guide_list() { return _guide_list; }
  std::vector<ContestPin>& get_pin_list() { return _pin_list; }
  std::vector<ContestSegment>& get_routing_segment_list() { return _routing_segment_list; }

  std::string get_net_name() const { return _net_name; }
  ContestPin* get_driver_pin() const { return _driver_pin; }
  std::vector<ContestPin*> get_sink_pins() const { return _sink_pins; }
  std::vector<ContestPin*> get_pins() const;

  Point<int32_t> get_lower_point() const;
  Point<int32_t> get_upper_point() const;
  int32_t get_hpwl() const;
  float get_netweight() const{ return _netweight; }
  int get_centrality() const { return _centrality; }
  bool get_traversed() const {return _traversed;}
  float get_itop_weight() const { return _itop_weight; }
  int get_id() const { return _id; }

  bool isDontCareNet() const { return _net_type == ContestNET_TYPE::kDontCare; }
  //待办
  bool isClockNet() const { return _net_type == ContestNET_TYPE::kClockNet;}


  // setter
  void set_net_name(const std::string net_name) { _net_name = net_name; }
  void set_guide_list(const std::vector<ContestGuide>& guide_list) { _guide_list = guide_list; }
  void set_pin_list(const std::vector<ContestPin>& pin_list) { _pin_list = pin_list; }
  void set_routing_segment_list(const std::vector<ContestSegment>& routing_segment_list) { _routing_segment_list = routing_segment_list; }
  // function
  std::optional<ContestPin*> isRealPin(ContestCoord& coord)
  {
    auto found_iter = std::find_if(_pin_list.begin(), _pin_list.end(), [&coord](auto& pin) { return pin.get_grid_coord() == coord; });
    if (found_iter != _pin_list.end()) {
      return &(*found_iter);
    }

    return std::nullopt;
  }

  void set_driver_pin(ContestPin* ContestPin) { _driver_pin =ContestPin; }
  void add_sink_pin(ContestPin* ContestPin) { _sink_pins.push_back(ContestPin); }
  void set_net_type(ContestNET_TYPE type) { _net_type = type; }
  void set_Contestnet_weight(float netweight) { _netweight = netweight; }
  void set_centrality(int ki){ _centrality = ki; }
  void set_traversed(bool is_traversed) { _traversed = is_traversed; }
  void set_itop_weight(float itop_weight) { _itop_weight = itop_weight; }

  void set_id(int id) { _id = id; }

 private:
  std::string _net_name;
  std::vector<ContestGuide> _guide_list;
  std::vector<ContestPin> _pin_list;
  std::vector<ContestSegment> _routing_segment_list;

  std::string _name;
  ContestNET_TYPE _net_type;
  ContestPin* _driver_pin;
  std::vector<ContestPin*> _sink_pins;

  int _id;

//   float _timing_netweight;
  float _netweight;
  float _itop_weight;
  float _k_i;
  bool _traversed;
  int _centrality;
public:
  std::unordered_map<ContestPin*,double> _early_weight;//存的是每个net的pin的weight
  std::unordered_map<ContestPin*,double> _late_weight;
};
inline ContestNet::ContestNet(std::string name) : _name(name), _net_type(ContestNET_TYPE::kNoNetType), _driver_pin(nullptr), _netweight(1.0){}

inline Point<int32_t> ContestNet::get_lower_point() const {
    int32_t lower_x = _driver_pin->get_center_coord().get_x();
    int32_t lower_y = _driver_pin->get_center_coord().get_y();

    for (auto sink_pin : _sink_pins) {
        if (sink_pin->get_center_coord().get_x() < lower_x) {
            lower_x = sink_pin->get_center_coord().get_x();
        }

        if (sink_pin->get_center_coord().get_y() < lower_y) {
            lower_y = sink_pin->get_center_coord().get_y();
        }
    }

    return Point<int32_t>(lower_x, lower_y);
}

inline Point<int32_t> ContestNet::get_upper_point() const {
    int32_t upper_x = _driver_pin->get_center_coord().get_x();
    int32_t upper_y = _driver_pin->get_center_coord().get_y();

    for (auto sink_pin : _sink_pins) {
        if (sink_pin->get_center_coord().get_x() > upper_x) {
            upper_x = sink_pin->get_center_coord().get_x();
        }

        if (sink_pin->get_center_coord().get_y() > upper_y) {
            upper_y = sink_pin->get_center_coord().get_y();
        }
    }

    return Point<int32_t>(upper_x, upper_y);
}

inline int32_t ContestNet::get_hpwl() const {
    Point<int32_t> lower_point = this->get_lower_point();
    Point<int32_t> upper_point = this->get_upper_point();

    return (upper_point.get_x() - lower_point.get_x()) + (upper_point.get_y() - lower_point.get_y());
}


inline std::vector<ContestPin*> ContestNet::get_pins() const
{
  std::vector<ContestPin*> ContestPin_list;
  if (_driver_pin != nullptr) {
    ContestPin_list.push_back(_driver_pin);
  }
  ContestPin_list.insert(ContestPin_list.end(),  _sink_pins.begin(), _sink_pins.end());//insert指的是在指定位置插入元素。
  return ContestPin_list;//第一个元素为driver pin
}





}  // namespace ieda_contest
